import socket
import threading
import time
import struct

# 服务器配置
UDP_IP = "0.0.0.0"  # 监听所有网络接口
UDP_PORT = 8080  # 默认端口号
BUFFER_SIZE = 1024  # 缓冲区大小

# 开机指令的字节序列
POWER_ON_CMD = b'\x01\x02\x03\x04'

# 设备状态信息
DEVICE_STATUS = {
    1: "电源状态: 开启",
    2: "CPU温度: 45°C",
    3: "内存使用: 32%",
    4: "网络状态: 良好",
    5: "系统运行时间: {}秒"
}

# 用于跟踪需要发送状态的客户端
active_clients = {}
client_lock = threading.Lock()


def send_device_status(client_addr):
    """向指定客户端每秒发送设备状态"""
    start_time = time.time()

    while True:
        with client_lock:
            if not active_clients.get(client_addr, False):
                break

        elapsed_time = int(time.time() - start_time)

        # 构建状态消息
        status_id = (int(time.time()) % 5) + 1  # 循环显示不同状态
        if status_id == 5:
            status_msg = DEVICE_STATUS[5].format(elapsed_time)
        else:
            status_msg = DEVICE_STATUS[status_id]

        # 添加时间戳
        timestamp = time.strftime("[%H:%M:%S] ")
        full_msg = timestamp + status_msg

        # 发送状态消息
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            # 修改目标地址端口为8080（保留原始IP）
            fixed_addr = (client_addr[0], 8080)  # 使用相同的IP，端口改为8080
            sock.sendto(full_msg.encode('utf-8'), fixed_addr)
            print(f"已发送状态到 {fixed_addr}: {full_msg}")
        except Exception as e:
            print(f"发送状态到 {fixed_addr} 失败: {str(e)}")
            break

        time.sleep(1)  # 每秒发送一次


def start_udp_server():
    # 创建UDP套接字
    global sock
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 绑定IP和端口
    sock.bind((UDP_IP, UDP_PORT))
    print(f"UDP服务器启动，监听端口: {UDP_PORT}")

    try:
        while True:
            # 接收数据
            data, addr = sock.recvfrom(BUFFER_SIZE)
            client_ip, client_port = addr

            # 打印接收信息
            print(f"\n[{time.strftime('%H:%M:%S')}] 收到来自 {client_ip}:{client_port} 的消息:")
            print(f"原始数据: {data}")

            # 检查是否是开机指令
            if data == POWER_ON_CMD:
                print(">>>> 收到开机指令 <<<<")

                # 检查是否已为此客户端启动线程
                with client_lock:
                    if addr not in active_clients or not active_clients[addr]:
                        active_clients[addr] = True
                        # 启动状态发送线程
                        threading.Thread(target=send_device_status, args=(addr,), daemon=True).start()

                # 发送确认响应
                response = "SERVER_OK: 设备正在启动..."
                sock.sendto(response.encode('utf-8'), addr)
                print(f"已发送响应: {response}")
                continue

            try:
                # 尝试解码为UTF-8
                decoded = data.decode('utf-8')
                print(f"解码内容: {decoded}")

                # 检查是否是测试消息
                if decoded == "UDP_TEST":
                    # 发送响应
                    response = "SERVER_OK"
                    sock.sendto(response.encode('utf-8'), addr)
                    print(f"已发送响应: {response}")
                else:
                    # 回显消息
                    sock.sendto(data, addr)
                    print(f"已回显消息")
            except UnicodeDecodeError:
                # 处理二进制数据
                print("二进制数据，无法解码")
                sock.sendto(b"BINARY_RECEIVED", addr)

    except KeyboardInterrupt:
        print("\n服务器正在停止...")
    except Exception as e:
        print(f"服务器错误: {str(e)}")
    finally:
        # 清理资源
        with client_lock:
            for addr in list(active_clients.keys()):
                active_clients[addr] = False
        sock.close()
        print("服务器已停止")


if __name__ == "__main__":
    start_udp_server()